#ifndef CARD_H
#define CARD_H

#include <exception>
#include <list>
#include <string>
#include <sstream>
#include <iostream>
#include <ctime>

#include "DataFlow.h"


using namespace std;

#define BETWEEN(a, b) (rand() % ((b) - (a) + 1) + (a))

class CCard 
{
public:	
	typedef unsigned int T_CardIndex;
	T_CardIndex Index;
	bool AssignedIndex;
	string Value;
public:
	CCard(string s, T_CardIndex d) : Value(s) , Index(d), AssignedIndex(true) {}
	CCard(string s) : Value(s) , AssignedIndex(false) {}
	CCard() : AssignedIndex(false) {}
};


class CCardSet : public list<CCard *>
{
public:
	
	iterator operator[] ( size_type n )
	{
		iterator it = begin();
		if (n >= size()) return it;
		while ( n > 0 ) 
		{
			n--;
			it++;
		}
		return it;
	}

	void MoveBack( iterator position )
	{
		CCard *c = *position;
		erase(position);
		push_back(c);
	}

	void Exchange( iterator a, iterator b)
	{
		value_type vt;
		vt = *a;
		*a = *b;
		*b = vt;
	}

	void SortByIndex()
	{
		iterator it;
		stringstream ss;
		for (unsigned int i = 0; i < size(); i ++)
		{
			it = FindByIndex(i);
			if (it == end()) {
				ss << "Card of Index " << i << " not found.";
				throw(runtime_error(ss.str()));
			}
			Exchange(operator[](i), it);
		}
	}

	void AssignIndex()
	{
		int i = 0;
		for (iterator it = begin(); it != end(); it++)
		{
			(*it)->Index = i;
			i++;
			(*it)->AssignedIndex = true;
		}
	}

	iterator FindByIndex(CCard::T_CardIndex d)
	{
		for (iterator it = begin(); it != end(); it++)
		{
			if ((*it)->Index == d)
				return it;
		}
		return end();
	}

	CCardSet RandChoose(int num) const
	{
		CCardSet set;
		if ( num <= 0 ) return set;
		set = *this;
		set.Wash();
		int pop = set.size() - num;
		while (pop-- > 0)
			set.pop_back();
		return set;
	}

	CCardSet PopFrontTo(int num)
	{
		CCardSet set;
		if ( num <= 0 ) return set;
		set.splice(set.begin(), *this, this->begin(), (*this)[num]);
		return set;
	}

	CCardSet GetSetFromData(const DataFlow &data)
	{
		CCardSet set;
		int num = data.GetListNumber(1);
		if (num <= 0) return set;
		for (int i = 0; i < num; i++)
		{
			CCard::T_CardIndex id = 0;
			memcpy(&id, data.GetListData(i, 1), 1);
			iterator it = FindByIndex(id);
			if (it != end()) set.push_back(*it);
		}
		return set;
	}

	void Wash()
	{
		srand( (unsigned)time(0) );

		size_type n = size();
		while ( n > 0 )
		{
			n--;
			MoveBack( operator[](BETWEEN(0, n)) );
		}
	}

private:

};

class NotInList
{
public:
	bool operator() (const CCard *c)
	{
		for (CCardSet::iterator it = set->begin(); it != set->end(); it++)
		{
			if ( *it == c )
				return 0;
		}
		return 1;
	}
	NotInList(CCardSet *s) : set(s) {}
private:
	CCardSet *set;
};


ostream &
operator << (ostream& out, const CCardSet &set);


#endif  //CARD_H